﻿/*
 * Author: Duncan Jenkins
 * 
 * Description: OCR Method using Point Template Matching
 * */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace LibraryCS {

    /// <summary>
    /// OCR method using Point Template matching
    /// </summary>
    public class PointTemplates : VisionAlgorithm {
        private String testsetDir, outputDir, templateDir = TemplatePreparation.templateDir;
        private List<Point> points = new List<Point>();
        private List<VImage> testsetBitmaps;
        private List<VImage> templateBitmaps = TemplatePreparation.templates;
        private double highestPercentage = 0;
        private VImage bestMatch = null;
        private List<String> percentages = new List<String>();
        private String endResult = "";
        private bool useDirectory = false;

        /// <summary>
        /// Constructor Point Templates
        /// </summary>
        /// <param name="name">Tag for this instance</param>
        public PointTemplates(String name) : base(name) {
            int pointCount = 5250;

            // Create a set number of points on (currently) 
            // random unique positions (later we might use the ANN to calculate where to put them);
            Random random = new Random();
        Hell:
            int togo = pointCount - points.Count;
            for (int i = 0; i < togo; i++) {
                points.Add(new Point(random.Next(100), random.Next(150)));
            }
            points = points.Distinct<Point>().ToList();
            if (points.Count != pointCount) {
                goto Hell;
            }
        }

        /// <summary>
        /// Overrided Do Algorithm method
        /// Starts the Point Template matching 
        /// </summary>
        /// <param name="sourceImage">Binarized Bitmap image ( black and white )</param>
        /// <returns>Template image that is the best match for the input</returns>

        public override Bitmap DoAlgorithm(Bitmap sourceImage) {
            endResult = "";
            percentages.Clear();
            if (useDirectory) {
                return processDirectory();
            } else {
                VImage source = new VImage(sourceImage);
                // Crop the image
                source = source.BoundingCrop();
                // Scale the image
                source = source.Scale(100, 150);
                source.localImage.Tag = "";
                return processImage(source);
            }
        }

        public Bitmap processDirectory() {
            for (int i = 0; i < testsetBitmaps.Count; i++) {
                processImage(testsetBitmaps[i]);
            }

            if (File.Exists(outputDir + "classified.csv")) {
                File.Delete(outputDir + "classified.csv");
            }
            StreamWriter sw = new StreamWriter(outputDir + "classified.csv");
            sw.WriteLine("Input file;Matched %;Classified as");
            sw.WriteLine("");

            foreach (string s in percentages) {
                sw.WriteLine(s);
                Debug.WriteLine(s);
            }
            sw.WriteLine("");
            sw.WriteLine("End result;" + endResult);
            Debug.WriteLine("End result;" + endResult);

            sw.Close();

            Bitmap result = new Bitmap(800, 600);
            Graphics g = Graphics.FromImage(result);
            g.Clear(Color.White);
            Font font = new Font(FontFamily.GenericSansSerif, 30, FontStyle.Regular, GraphicsUnit.Pixel);
            g.DrawString(endResult, font, new SolidBrush(Color.Black), 0, 0);
            return result;
        }

        public Bitmap processImage(VImage input) {
            highestPercentage = 0;
            bestMatch = null;

            // Compare all points
            for (int t = 0; t < templateBitmaps.Count; t++) {
                double percentage = 0;
                double matching = 0;
                VImage template = templateBitmaps[t];
                //Debug
                input.localImage.Save("T:\\Coding\\TestStuff\\input.jpg");
                template.localImage.Save("T:\\Coding\\TestStuff\\template.jpg");
                for (int p = 0; p < points.Count; p++) {
                    int compareIndex = points[p].Y * template.Width + points[p].X;
                    if (template.RedPixels[compareIndex] == input.RedPixels[compareIndex]) {
                        matching++;
                    }
                }
                percentage = (matching / points.Count) * 100;
                percentage = Math.Round(percentage, 2);

                if (percentage > highestPercentage) {
                    highestPercentage = percentage;
                    bestMatch = template;
                    Debug.WriteLine("better %: " + input.localImage.Tag + ";" + highestPercentage + ";" + bestMatch.localImage.Tag);
                    if (percentage > 90) {
                        break;
                    }
                }
            }
            if (highestPercentage < 60) {
                // Not a character
                Debug.WriteLine("NAC - Not a character");
            }
            percentages.Add("" + input.localImage.Tag + ";" + highestPercentage + ";" + bestMatch.localImage.Tag);
            Debug.WriteLine("" + input.localImage.Tag + ";" + highestPercentage + ";" + bestMatch.localImage.Tag);
            endResult += bestMatch.localImage.Tag;

            return bestMatch.localImage;
        }

        #region GUI Functions

        public override List<Control> createControls() {
            List<Control> Controls = new List<Control>();

            Label lbUseDir = new Label();
            lbUseDir.AutoSize = true;
            lbUseDir.Text = "Use directory";
            lbUseDir.Name = "lbUseDir";

            CheckBox cbUseDir = new CheckBox();
            cbUseDir.Name = "cbUseDir";
            cbUseDir.Checked = false;

            Label lbTestsetDir = new Label();
            lbTestsetDir.AutoSize = true;
            lbTestsetDir.Text = "Test set directory";
            lbTestsetDir.Name = "lbTestsetDir";

            TextBox tbTestsetDir = new TextBox();
            tbTestsetDir.Name = "tbTestsetDir";
            tbTestsetDir.AcceptsReturn = false;
            tbTestsetDir.Multiline = false;
            tbTestsetDir.Size = new Size(50, 25);
            tbTestsetDir.Text = "..\\..\\..\\Resources\\TestSet_input\\";

            Label lbOutputDir = new Label();
            lbOutputDir.AutoSize = true;
            lbOutputDir.Text = "Output directory";
            lbOutputDir.Name = "lbOutputDir";

            TextBox tbOutputDir = new TextBox();
            tbOutputDir.Name = "tbOutputDir";
            tbOutputDir.AcceptsReturn = false;
            tbOutputDir.Multiline = false;
            tbOutputDir.Size = new Size(50, 25);
            tbOutputDir.Text = "..\\..\\..\\Resources\\TestSet_output\\";

            Controls.Add(cbUseDir);
            Controls.Add(lbUseDir);
            Controls.Add(tbTestsetDir);
            Controls.Add(lbTestsetDir);
            Controls.Add(tbOutputDir);
            Controls.Add(lbOutputDir);

            return Controls;
        }

        public override void setSettings(List<object> settings) {
            useDirectory = ((CheckBox)settings[0]).Checked;
            testsetDir = ((TextBox)settings[1]).Text;
            outputDir = ((TextBox)settings[2]).Text;

            if (useDirectory) {
                // Prepare Test set
                testsetBitmaps = TemplatePreparation.prepareTestSet(testsetDir, outputDir);
            }
        }

        #endregion
    }
}
